<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
	
	<link rel="stylesheet" href="styles.css">

	<script type="importmap">
	  {
		"imports": {
		  "three": "https://cdn.jsdelivr.net/npm/three@0.164.0/build/three.module.js",
		  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.164.0/examples/jsm/",
		  "pet/": "https://cdn.jsdelivr.net/npm/pet-gen@1.7.1/src/"
		}
	  }
	</script>
</head>

<body>
	<div class="header white">
		<h1 class="white">Equirectangular AO map</h1>
		<h3 class="white">Ambient occlusion texture is generated at runtime by <a href="https://boytchev.github.io/texture-generator/docs/polka-dots.html">polka-dots.js</a></h3>
	</div>
	
	<div class="footnote white">
		<a href="#" onclick="window.history.back(); return false;">Back</a>
	</div>
	
	<script type="module">

		import * as THREE from "three";
		import { OrbitControls } from "three/addons/controls/OrbitControls.js";
		import * as PET from "pet/patterns/polka-dots.js";



		// setting up the scene

		var scene = new THREE.Scene();
		scene.background = new THREE.Color( 0x202020 );

		var camera = new THREE.PerspectiveCamera( 40, innerWidth/innerHeight );
		camera.position.set( 0, 0, 10 );
		camera.lookAt( scene.position );

		var renderer = new THREE.WebGLRenderer( { antialias: true } );
		renderer.setSize( innerWidth, innerHeight );
		renderer.setAnimationLoop( animationLoop );
		document.body.appendChild( renderer.domElement );

		window.addEventListener( "resize", ( /*event*/ ) => {

			camera.aspect = innerWidth/innerHeight;
			camera.updateProjectionMatrix( );
			renderer.setSize( innerWidth, innerHeight );

		} );

		var hiddenCamera = camera.clone();
		hiddenCamera.position.set( 0, 0, 1 );

		var controls = new OrbitControls( hiddenCamera, renderer.domElement );
		controls.enableDamping = true;
		controls.autoRotate = !true;
		controls.autoRotateSpeed = 0.5;

		var light = new THREE.PointLight( 'white', 30 );
		light.position.set( 0, 0, 10 );
		scene.add( light );

		scene.add( new THREE.AmbientLight( 'white', 2 ) );



		// generator of bumps

		function buildBumps( positions, material ) {

			var bumps = new THREE.Group(),
				geometry = new THREE.SphereGeometry( 0.2 ).translate( 0, 0, -1.05 );

			for ( var pos of positions.points ) {

				var bump = new THREE.Mesh( geometry, material );
				bump.position.copy( pos );
				bump.lookAt( 0, 0, 0 );

				bumps.add( bump );

			}

			return bumps;

		}



		// left ball

		var leftMaterial = new THREE.MeshPhysicalMaterial( {
			color: 'white',
			metalness: 1,
			roughness: 0,
			emissive: 'white',
			emissiveIntensity: 1.5,
		} );

		var leftBall = new THREE.Mesh(
			new THREE.SphereGeometry( 2 ),
			PET.material( new THREE.MeshPhysicalMaterial( {
				metalness: 0.5,
				roughness: 1,
				aoMap: PET.texture( { width: 256, layout: 9, blur: 90, scale: 40 } ),
			} ) )
		);

		leftBall.add( buildBumps( PET.defaults.$layouts[ 8 ], leftMaterial ) );
		leftBall.position.x = -2.5;
		scene.add( leftBall );



		// right ball

		var rightMaterial = leftMaterial.clone();

		var rightBall = new THREE.Mesh(
			new THREE.SphereGeometry( 2, 64, 32 ),
			PET.material( new THREE.MeshPhysicalMaterial( {
				metalness: 0.5,
				roughness: 1,
				aoMap: PET.texture( { width: 512, layout: 10, blur: 80, scale: 40 } ),
			} ) )
		);

		rightBall.add( buildBumps( PET.defaults.$layouts[ 9 ], rightMaterial ) );
		rightBall.position.x = 2.5;
		scene.add( rightBall );



		// main animation loop to turn lights on-off

		function animationLoop( t ) 		{

			t = t/1300;

			// control left ball

			var onOff = Math.sin( t )**5 - Math.sin( 3*t )**5 > 0;

			leftBall.material.color.setStyle( onOff ? 'SteelBlue' : 'LightSteelBlue' );
			leftBall.material.aoMapIntensity = onOff ? 2 : -8;
			leftMaterial.emissiveIntensity = onOff ? 0 : 1;

			// control right ball

			onOff = Math.cos( 3*t )**5 - Math.sin( t )**5 > 0;

			rightBall.material.color.setStyle( onOff ? 'SteelBlue' : 'LightSteelBlue' );
			rightBall.material.aoMapIntensity = onOff ? 2 : -8;
			rightMaterial.emissiveIntensity = onOff ? 0 : 1.5;

			// control ball rotation

			controls.update( );

			for ( var ball of [ leftBall, rightBall ]) {

				ball.scale.setScalar( 1/controls.getDistance() );
				ball.quaternion.copy( hiddenCamera.quaternion ).conjugate();

			}

			renderer.render( scene, camera );

		}

	</script>
</body>
</html>